package edu.zjut.hjg.saas.biz.service.impl;

import java.util.List;

import edu.zjut.hjg.saas.biz.dao.ConsumptionDao;
import edu.zjut.hjg.saas.biz.dao.KindergartenDao;
import edu.zjut.hjg.saas.biz.dao.SubscribeDao;
import edu.zjut.hjg.saas.biz.dao.TenantDao;
import edu.zjut.hjg.saas.biz.model.Consumption;
import edu.zjut.hjg.saas.biz.model.Kindergarten;
import edu.zjut.hjg.saas.biz.model.PriceType;
import edu.zjut.hjg.saas.biz.model.Subscribe;
import edu.zjut.hjg.saas.biz.model.Tenant;
import edu.zjut.hjg.saas.biz.service.BillingService;
import edu.zjut.hjg.saas.biz.service.EmailService;
import edu.zjut.hjg.saas.biz.support.AppStatus;
import edu.zjut.hjg.saas.biz.support.ChargeStatus;
import edu.zjut.hjg.saas.biz.util.PriceTypeUtil;

public class BillingServiceImpl implements BillingService {
    private static final int BATCH_LIMIT = 100;

    private SubscribeDao     subscribeDao;

    private ConsumptionDao   consumptionDao;

    private KindergartenDao  kindergartenDao;

    private TenantDao        tenantDao;

    private EmailService     emailService;

    public void setEmailService(EmailService emailService) {
        this.emailService = emailService;
    }

    public void setTenantDao(TenantDao tenantDao) {
        this.tenantDao = tenantDao;
    }

    public void setSubscribeDao(SubscribeDao subscribeDao) {
        this.subscribeDao = subscribeDao;
    }

    public void setConsumptionDao(ConsumptionDao consumptionDao) {
        this.consumptionDao = consumptionDao;
    }

    public void setKindergartenDao(KindergartenDao kindergartenDao) {
        this.kindergartenDao = kindergartenDao;
    }

    @Override
    public void dailyBilling() {
        billing(-1);
    }

    private void billing(int startAppId) {
        List<Subscribe> subscribes = subscribeDao.listByKindergartenStatus(AppStatus.ENABLED,
                startAppId, BATCH_LIMIT);
        if (subscribes.isEmpty()) {
            return;
        }
        int max = startAppId;
        for (Subscribe subscribe : subscribes) {
            int id = subscribe.getId();
            max = id > max ? id : max;
            ChargeStatus chargeStatus = subscribe.getChargeStatus();
            switch (chargeStatus) {
                case FREE_TRIAL:
                    billingFreeTrail(subscribe);
                    break;
                case CHARGING:
                    billingCharging(subscribe);
                    break;
                default:
            }
        }
        billing(max);
    }

    private void billingFreeTrail(Subscribe subscribe) {
        Kindergarten app = subscribe.getKindergarten();
        PriceType priceType = subscribe.getPriceType();
        Tenant tenant = app.getTenant();
        if (PriceTypeUtil.isFreeTrailEnded(app.getStartDate())) {
            // 试用期到期，产生一条免费的消费记录
            double balance = tenant.getBalance();
            if (balance < priceType.getPrice()) {
                emailService.sendEmail(tenant.getEmail(), "您的幼儿园网站", rendEmail(subscribe,
                        "免费试用期到期，余额不足，已经停用，请继费用重新启用"));
                // 余额不足，停用网站
                app.setStatus(AppStatus.DISABLED);
                pricing(0.0, subscribe, "免费试用期结束消费，余额不足，停用网站");
                kindergartenDao.update(app);
            } else {
                // 转成计费期
                emailService.sendEmail(tenant.getEmail(), "您的幼儿园网站", rendEmail(subscribe,
                        "免费试用期到期，转成收费使用期"));
                subscribe.setChargeStatus(ChargeStatus.CHARGING);
                pricing(0.0, subscribe, "免费试用期结束消费，转为收费期");
                subscribeDao.update(subscribe);
            }
        }
    }

    private void billingCharging(Subscribe subscribe) {
        Kindergarten app = subscribe.getKindergarten();
        PriceType priceType = subscribe.getPriceType();
        Tenant tenant = app.getTenant();
        Double price = priceType.getPrice();
        if (PriceTypeUtil.isChargingEnded(app.getEndDate())) {
            // 租期到期
            emailService.sendEmail(tenant.getEmail(), "您的幼儿园网站", rendEmail(subscribe,
                    "租期到期，已经停用，请进行续租"));
            pricing(price, subscribe, "租期到期，停用网站");
            app.setStatus(AppStatus.DISABLED);
            kindergartenDao.update(app);
            return;
        }
        // 未到期，如果余额不足，则停用网站
        if (tenant.getBalance() < price) {
            emailService.sendEmail(tenant.getEmail(), "您的幼儿园网站", rendEmail(subscribe, "因为余额不足以支付["
                    + price + "元/" + priceType.getUnit() + "]的单价，已经停用，请及时续费"));
            // 余额不足，停用网站
            double spend = PriceTypeUtil.computeLastSpend(app.getStartDate(), priceType);
            pricing(spend, subscribe, "余额不足或欠费，停用网站");
            app.setStatus(AppStatus.DISABLED);
            kindergartenDao.update(app);
            return;
        }

        // 刚好是一个计费周期，则进行正常计费
        if (PriceTypeUtil.isChargingDay(app.getStartDate(), priceType.getChargeType())) {
            pricing(price, subscribe, "到达一个计费周期");
        }
    }

    private void pricing(double spend, Subscribe subscribe, String description) {
        Tenant tenant = subscribe.getKindergarten().getTenant();
        Consumption consumption = new Consumption();
        consumption.setDescription(description);
        consumption.setSpend(spend);
        consumption.setSubscribe(subscribe);
        consumption.setTenant(tenant);
        consumptionDao.create(consumption);
        tenant.setBalance(tenant.getBalance() - spend);
        tenantDao.update(tenant);
    }

    private String rendEmail(Subscribe subscribe, String content) {
        Kindergarten app = subscribe.getKindergarten();
        Tenant tenant = app.getTenant();
        StringBuffer buffer = new StringBuffer("尊敬的用户");
        buffer.append(tenant.getLoginId());
        buffer.append("(");
        buffer.append(tenant.getName());
        buffer.append(")，您好：<br />");
        buffer.append("您的幼儿园网站");
        buffer.append(app.getName());
        buffer.append("，");
        buffer.append(content);
        buffer.append("<br />");
        buffer.append("特此提醒，该邮件为系统邮件，请勿回复！");
        return buffer.toString();
    }
}
